﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using UCL.Powersource;

namespace PowersourceUIToolkit
{
    /// <summary>
    ///   Hosts dependency properties for binding.
    /// </summary>
    public static class Bind
    {
        /// <summary>
        ///   Allows binding on an existing View. Use this on root UserControls, Pages and Windows; not in a DataTemplate.
        /// </summary>
        public static DependencyProperty ModelProperty =
            DependencyProperty.RegisterAttached(
                "Model",
                typeof(object),
                typeof(Bind),
                new PropertyMetadata(ModelChanged)
                );

        /// <summary>
        ///   Allows binding on an existing View without setting the data Context. Use this from within a DataTemplate.
        /// </summary>
        public static DependencyProperty ModelWithoutContextProperty =
            DependencyProperty.RegisterAttached(
                "ModelWithoutContext",
                typeof(object),
                typeof(Bind),
                new PropertyMetadata(ModelWithoutContextChanged)
                );

        internal static DependencyProperty NoContextProperty =
            DependencyProperty.RegisterAttached(
                "NoContext",
                typeof(bool),
                typeof(Bind),
                new PropertyMetadata(false)
                );

        /// <summary>
        ///   Gets the model to bind to.
        /// </summary>
        /// <param name = "dependencyObject">The dependency object to bind to.</param>
        /// <returns>The model.</returns>
        public static object GetModelWithoutContext(DependencyObject dependencyObject)
        {
            return dependencyObject.GetValue(ModelWithoutContextProperty);
        }

        /// <summary>
        ///   Sets the model to bind to.
        /// </summary>
        /// <param name = "dependencyObject">The dependency object to bind to.</param>
        /// <param name = "value">The model.</param>
        public static void SetModelWithoutContext(DependencyObject dependencyObject, object value)
        {
            dependencyObject.SetValue(ModelWithoutContextProperty, value);
        }

        /// <summary>
        ///   Gets the model to bind to.
        /// </summary>
        /// <param name = "dependencyObject">The dependency object to bind to.</param>
        /// <returns>The model.</returns>
        public static object GetModel(DependencyObject dependencyObject)
        {
            return dependencyObject.GetValue(ModelProperty);
        }

        /// <summary>
        ///   Sets the model to bind to.
        /// </summary>
        /// <param name = "dependencyObject">The dependency object to bind to.</param>
        /// <param name = "value">The model.</param>
        public static void SetModel(DependencyObject dependencyObject, object value)
        {
            dependencyObject.SetValue(ModelProperty, value);
        }

        static ILog Log=LogManager.GetLog(typeof(Bind));

        static void ModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            
            if (e.NewValue == null || e.NewValue == e.OldValue)
            {
                return;
            }
            Log.Warn("ModelChanged ignored for NEWV={0}, OLDV={1}", e.NewValue, e.OldValue);
            //var fe = d as FrameworkElement;
            //if (fe == null)
            //{
            //    return;
            //}

            //View.ExecuteOnLoad(fe, delegate
            //{
            //    var target = e.NewValue;
            //    var containerKey = e.NewValue as string;

            //    if (containerKey != null)
            //    {
            //        target = IoC.GetInstance(null, containerKey);
            //    }

            //    d.SetValue(View.IsScopeRootProperty, true);

            //    var Context = string.IsNullOrEmpty(fe.Name)
            //                      ? fe.GetHashCode().ToString()
            //                      : fe.Name;

            //    ViewModelBinder.Bind(target, d, Context);
            //});
        }

        static void ModelWithoutContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ( e.NewValue == null || e.NewValue == e.OldValue)
            {
                return;
            }
            Log.Warn("ModelChanged ignored for NEWV={0}, OLDV={1}", e.NewValue, e.OldValue);

            //var fe = d as FrameworkElement;
            //if (fe == null)
            //{
            //    return;
            //}

            //View.ExecuteOnLoad(fe, delegate
            //{
            //    var target = e.NewValue;
            //    var containerKey = e.NewValue as string;

            //    if (containerKey != null)
            //    {
            //        target = IoC.GetInstance(null, containerKey);
            //    }

            //    d.SetValue(View.IsScopeRootProperty, true);

            //    var Context = string.IsNullOrEmpty(fe.Name)
            //                      ? fe.GetHashCode().ToString()
            //                      : fe.Name;

            //    d.SetValue(NoContextProperty, true);
            //    ViewModelBinder.Bind(target, d, Context);
            //});
        }

        /// <summary>
        /// Allows application of conventions at design-time.
        /// </summary>
        public static DependencyProperty AtDesignTimeProperty =
            DependencyProperty.RegisterAttached(
                "AtDesignTime",
                typeof(bool),
                typeof(Bind),
                new PropertyMetadata(AtDesignTimeChanged)
                );

#if NET
        [AttachedPropertyBrowsableForTypeAttribute(typeof(DependencyObject))]
#endif
        /// <summary>
        /// Gets whether or not conventions are being applied at design-time.
        /// </summary>
        /// <param name="dependencyObject">The ui to apply conventions to.</param>
        /// <returns>Whether or not conventions are applied.</returns>
        public static bool GetAtDesignTime(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(AtDesignTimeProperty);
        }

        /// <summary>
        /// Sets whether or not do bind conventions at design-time.
        /// </summary>
        /// <param name="dependencyObject">The ui to apply conventions to.</param>
        /// <param name="value">Whether or not to apply conventions.</param>
        public static void SetAtDesignTime(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(AtDesignTimeProperty, value);
        }

        static void AtDesignTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //if (!Execute.InDesignMode)
                //return;

            //BindingOperations.SetBinding(d, DataContextProperty, (bool)e.NewValue ? new Binding() : null);
        }

        static readonly DependencyProperty DataContextProperty =
            DependencyProperty.RegisterAttached(
                "DataContext",
                typeof(object),
                typeof(Bind),
                new PropertyMetadata(DataContextChanged)
                );

        static void DataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //if (!Execute.InDesignMode)
            //    return;

            //var enable = d.GetValue(AtDesignTimeProperty);
            //if (enable == null || ((bool)enable) == false || e.NewValue == null)
            //    return;

            //var fe = d as FrameworkElement;
            //if (fe == null)
            //    return;

            //ViewModelBinder.Bind(e.NewValue, d, string.IsNullOrEmpty(fe.Name) ? fe.GetHashCode().ToString() : fe.Name);
        }
    }

}
